package com.kehutong.crm.service.impl;

import com.kehutong.common.DoveClient;
import com.kehutong.common.errcode.Result;
import com.kehutong.common.util.NumberUtils;
import com.kehutong.crm.dao.DemandForecastDao;
import com.kehutong.crm.dto.*;
import com.kehutong.crm.entity.DemandForecast;
import com.kehutong.crm.entity.DemandForecastSequence;
import com.kehutong.crm.enums.DemandForecastTypeEnum;
import com.kehutong.crm.service.DemandForecastSequenceService;
import com.kehutong.crm.service.DemandForecastService;
import com.kehutong.crm.utils.DateUtils;
import com.tencentcloudapi.common.Credential;
import org.coraframework.authz.Subject;
import org.coraframework.authz.SubjectUtil;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.orm.jdbc.connection.ThreadLocalCache;
import org.coraframework.orm.jdbc.execute.Condition;
import org.coraframework.orm.jdbc.execute.PageCondition;
import org.coraframework.orm.jdbc.execute.QueryCondition;
import org.coraframework.orm.jdbc.execute.entity.FindArray;
import org.coraframework.util.Objects;
import org.coraframework.util.secret.MD5;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 需求预测服务接口实现类
 *
 * @author wupengfei
 */
public class DemandForecastServiceImpl implements DemandForecastService {

    private static final Logger logger = LoggerFactory.getLogger(DemandForecastServiceImpl.class);

    @Inject
    private DoveClient doveClient;

    @Inject
    private JdbcSession jdbcSession;

    @Inject
    private DemandForecastDao demandForecastDao;

    @Inject
    private DemandForecastSequenceService demandForecastSequenceService;

    @Override
    public Object forecast(JSONObject account, DemandForecastTypeEnum typeEnum) throws Exception {
        logger.info("预测mobile=" + account.toJSONString() + ",typeEnum=" + typeEnum);

        // 保存企业id
        JSONArray khtIdArray = account.getJSONArray("khtIds");
        List<String> corpIdList = new ArrayList<>();
        if (khtIdArray != null) {
            for (Object o : khtIdArray) {
                corpIdList.add(o.toString());
            }
        }

        // 获取本周一日期
        Date mondayDate = DateUtils.getThisWeekMonday(new Date());
        String monday = DateUtils.format(mondayDate, DateUtils.YYYY_MM_DD);

        // 保存预测
        return doForecast(account.getString("mobile"), account.getString("id"), corpIdList, typeEnum, monday);
    }

    @Override
    public Object forecast(String mobile, String type) throws Exception {
        logger.info("预测mobile=" + mobile + ",type=" + type);

        // 获取类型枚举
        Map<String, DemandForecastTypeEnum> enumMap = DemandForecastTypeEnum.getEnumMap();
        DemandForecastTypeEnum typeEnum = enumMap.get(type);
        if (typeEnum == null) {
            return Result.badArgument();
        }

        // 获取账号
        JSONObject accountResult = doveClient.post("/auth/account/service/getAccount", (http) -> {
            JSONObject body = new JSONObject();
            body.put("mobile", mobile);
            http.setBody(body.toJSONString());
        });
        if (accountResult == null) {
            return Result.badArgument();
        }
        JSONObject account = accountResult.getJSONObject("data");
        if (account == null) {
            return Result.badArgument();
        }
        return forecast(account, typeEnum);
    }

    @Override
    public Page<DemandForecastResDto> getByType(JSONObject jsonObject) throws Exception {
        logger.info("根据类型获取预测数据");
        // 结果
        Page<DemandForecastResDto> result = new Page<>();

        // 获取本周一日期
        Date mondayDate = DateUtils.getThisWeekMonday(new Date());
        String monday = DateUtils.format(mondayDate, DateUtils.YYYY_MM_DD);

        // 若搜索不为空
        Page page = null;
        String mobile = jsonObject.getString("mobile");
        Integer forecastValue = jsonObject.getInteger("forecastValue");
        if (!Objects.isBlank(mobile) || forecastValue != null) {
            PageCondition condition = Condition.createPage(false);
            condition.eq("weekStartDate", monday).and().eq("type", jsonObject.getString("type"))
                    .and().eq("corpId", ThreadLocalCache.current().getCorpId());
            if (!Objects.isBlank(mobile)) {
                condition.and().eq("mobile", mobile);
            }
            if (forecastValue != null) {
                condition.and().eq("forecastValue", forecastValue);
            }
            condition.page(jsonObject);
            page = demandForecastDao.getPage(condition);
            List<DemandForecast> list = page.getList();
            List<DemandForecastResDto> resultList = convert(list, mondayDate, monday);
            result.setList(resultList);
        } else {
            // 获取需求预测排序数据
            page = jdbcSession.findPage(DemandForecastSequence.class).eq("corpId", ThreadLocalCache.current().getCorpId())
                    .and().eq(jsonObject, "type").page(jsonObject).order("sequence").exe();
            List<DemandForecastSequence> list = page.getList();
            if (Objects.nonEmpty(list)) {
                // 获取用户id集合
                List<String> userIdList = new ArrayList<>();
                Map<String, DemandForecastSequence> demandForecastSequenceMap = new HashMap<>();
                for (DemandForecastSequence each : list) {
                    userIdList.add(each.getUserId());
                    demandForecastSequenceMap.put(each.getUserId(), each);
                }

                // 获取需求预测
                List<DemandForecast> demandForecastList = jdbcSession.findArray(DemandForecast.class).in("userId", userIdList).and()
                        .eq("weekStartDate", monday).and().eq(jsonObject, "type").and()
                        .findInSet("corpIds", ThreadLocalCache.current().getCorpId()).exe();
                Map<String, DemandForecast> demandForecastMap = demandForecastList.stream().collect(Collectors.toMap(DemandForecast::getUserId, Function.identity()));
                demandForecastList = new ArrayList<>();
                for (String each : userIdList) {
                    DemandForecast demandForecast = demandForecastMap.get(each);
                    if (demandForecast != null) {
                        demandForecastList.add(demandForecast);
                    }
                }

                // 转换结果
                List<DemandForecastResDto> resultList = convert(demandForecastList, mondayDate, monday);
                for (DemandForecastResDto each : resultList) {
                    each.setId(demandForecastSequenceMap.get(each.getUserId()).getId());
                }
                result.setList(resultList);
            }
        }

        result.setCount(page.getCount());
        result.setOffSet(page.getOffSet());
        result.setPageCount(page.getPageCount());
        result.setPageNo(page.getPageNo());
        result.setPageSize(page.getPageSize());
        return result;
    }

    @Override
    public List<DemandForecastResDto> getByUserId(String userId) throws Exception {
        logger.info("获取用户的预测数据userId=" + userId);
        // 获取本周一日期
        Date thisWeekMondayDate = DateUtils.getThisWeekMonday(new Date());
        String thisWeekMonday = DateUtils.format(thisWeekMondayDate, DateUtils.YYYY_MM_DD);

        // 获取用户本周的预测
        List<DemandForecast> demandForecastList = jdbcSession.findArray(DemandForecast.class).eq("userId", userId).and()
                .eq("weekStartDate", thisWeekMonday).exe();
        return convert(demandForecastList, thisWeekMondayDate, thisWeekMonday);
    }

    @Override
    public List<DemandForecastStatisticsDto> getStatisticsByCorpIdAndType() {
        logger.info("需求预测统计");
        List<DemandForecastStatisticsDto> result = new ArrayList<>();

        // 获取本周一日期
        Date thisWeekMondayDate = DateUtils.getThisWeekMonday(new Date());
        String thisWeekMonday = DateUtils.format(thisWeekMondayDate, DateUtils.YYYY_MM_DD);

        // 获取预测枚举
        Map<String, DemandForecastTypeEnum> enumMap = DemandForecastTypeEnum.getEnumMap();

        // 统计企业
        QueryCondition query = Condition.createQuery();
        query.noEq("forecastValue", "0").and().eq("weekStartDate", thisWeekMonday);
        List<Map<String, Object>> dataList = demandForecastDao.statisticsCompany(query);
        if (Objects.nonEmpty(dataList)) {
            Map<String, DemandForecastStatisticsDto> corpMap = new HashMap<>();
            for (Map<String, Object> each : dataList) {
                String corpIds = each.get("corpIds").toString();
                String[] corpIdArray = corpIds.split("\\s*,\\s*");
                for (String eachCorpId : corpIdArray) {
                    String key = eachCorpId + "-" + each.get("type").toString();
                    DemandForecastStatisticsDto item = new DemandForecastStatisticsDto();
                    item.setCorpId(eachCorpId);
                    item.setType(each.get("type").toString());
                    item.setName(enumMap.get(each.get("type").toString()).getName());
                    item.setNumber(NumberUtils.toInt(each.get("number").toString()));
                    DemandForecastStatisticsDto demandForecastStatisticsDto = corpMap.get(key);
                    if (demandForecastStatisticsDto == null) {
                        corpMap.put(key, item);
                    } else {
                        demandForecastStatisticsDto.setNumber(demandForecastStatisticsDto.getNumber() + item.getNumber());
                    }
                }
            }
            result.addAll(corpMap.values());
        }
        return result;
    }

    @Override
    public List<String> getByTypeAndForecastValue(JSONObject jsonObject) {
        logger.info("获取符合预测的用户id");
        // 获取本周一日期
        Date thisWeekMondayDate = DateUtils.getThisWeekMonday(new Date());
        String thisWeekMonday = DateUtils.format(thisWeekMondayDate, DateUtils.YYYY_MM_DD);

        // 获取需求预测
        FindArray<DemandForecast> findArray = jdbcSession.findArray(DemandForecast.class).eq("weekStartDate", thisWeekMonday)
                .and().findInSet("corpIds", ThreadLocalCache.current().getCorpId()).and().markBegin();

        // 设置类型和预测值
        boolean isHasType = false;
        Map<String, DemandForecastTypeEnum> enumMap = DemandForecastTypeEnum.getEnumMap();
        Map<String, Integer> typeValueMap = new HashMap<>();
        for (Map.Entry<String, DemandForecastTypeEnum> entry : enumMap.entrySet()) {
            Integer value = jsonObject.getInteger(entry.getKey());
            if (value != null && value > 0) {
                typeValueMap.put(entry.getKey(), value);
            }
        }
        if (typeValueMap.size() > 0) {
            isHasType = true;
            List<String> typeList = new ArrayList<>(typeValueMap.keySet());
            for (int i = 0; i < typeList.size(); i++) {
                findArray.markBegin();
                findArray.eq("type", typeList.get(i)).and().eq("forecastValue", typeValueMap.get(typeList.get(i)));
                findArray.markEnd();
                if (i != typeList.size() - 1) {
                    findArray.or();
                }
            }
        }
        findArray.markEnd();

        if (isHasType) {
            List<DemandForecast> demandForecastList = findArray.exe();
            if (Objects.nonEmpty(demandForecastList)) {
                return demandForecastList.stream().map(DemandForecast::getUserId).distinct().collect(Collectors.toList());
            }
        }
        return new ArrayList<>();
    }

    private List<DemandForecastResDto> convert(List<DemandForecast> list, Date mondayDate, String monday) throws Exception {
        List<DemandForecastResDto> result = new ArrayList<>();
        StringBuilder idBuilder = new StringBuilder();
        List<String> userIdList = new ArrayList<>();
        for (DemandForecast each : list) {
            if (!userIdList.contains(each.getUserId())) {
                idBuilder.append(each.getUserId()).append(",");
                userIdList.add(each.getUserId());
            }
        }

        // 获取账号
        JSONObject accountResult = doveClient.post("/auth/account/service/getByIdList", (http) -> {
            JSONObject body = new JSONObject();
            body.put("idList", idBuilder.toString());
            http.setBody(body.toJSONString());
        });
        JSONArray accountArray = accountResult.getJSONArray("data");
        Map<String, JSONObject> accountMap = new HashMap<>();
        for (Object each : accountArray) {
            JSONObject account = (JSONObject) each;
            accountMap.put(account.getString("id"), account);
        }

        // 获取最近一个月的统计（按四周计算）
        Date monthMonday = getMonthMonday(mondayDate, -20);
        Condition condition = Condition.createQuery();
        condition.in("userId", userIdList).and().between("weekStartDate", DateUtils.format(monthMonday, DateUtils.YYYY_MM_DD), monday);
        List<Map<String, Object>> monthList = demandForecastDao.statisticsByUserAndDate(condition);
        Map<String, Map<String, Integer>> monthValueMap = getStatisticsForecastValue(monthList);

        // 获取最近三个月的统计（按十二周计算）
        Date threeMonthMonday = getMonthMonday(mondayDate, -77);
        condition = Condition.createQuery();
        condition.in("userId", userIdList).and().between("weekStartDate", DateUtils.format(threeMonthMonday, DateUtils.YYYY_MM_DD), monday);
        List<Map<String, Object>> threeMonthList = demandForecastDao.statisticsByUserAndDate(condition);
        Map<String, Map<String, Integer>> threeMonthValueMap = getStatisticsForecastValue(threeMonthList);

        Map<String, DemandForecastTypeEnum> enumMap = DemandForecastTypeEnum.getEnumMap();
        for (DemandForecast each : list) {
            JSONObject account = accountMap.get(each.getUserId());
            DemandForecastResDto item = new DemandForecastResDto();
            item.setId(each.getId());
            item.setMobile(each.getMobile());
            item.setType(each.getType());
            item.setTypeName(enumMap.get(each.getType()).getName());
            item.setName(account.getString("realname"));
            item.setSequence(each.getSequence());
            item.setUserId(each.getUserId());
            item.setWeekForecastValue(each.getForecastValue());

            Map<String, Integer> userMap = monthValueMap.get(each.getUserId());
            if (userMap != null) {
                item.setMonthForecastValue(userMap.get(each.getType()));
            }
            userMap = threeMonthValueMap.get(each.getUserId());
            if (userMap != null) {
                item.setThreeMonthForecastValue(userMap.get(each.getType()));
            }
            result.add(item);
        }
        return result;
    }

    private Map<String, Map<String, Integer>> getStatisticsForecastValue(List<Map<String, Object>> monthList) {
        Map<String, Map<String, Integer>> result = new HashMap<>();
        if (monthList != null) {
            for (Map<String, Object> each : monthList) {
                int forecastValue = NumberUtils.toInt(each.get("forecastValue").toString());
                int number = NumberUtils.toInt(each.get("number").toString());
                Map<String, Integer> userMap = result.computeIfAbsent(each.get("userId").toString(), k -> new HashMap<>());
                userMap.put(each.get("type").toString(), forecastValue / number);
            }
        }
        return result;
    }

    private Date getMonthMonday(Date monday, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(monday);
        calendar.add(Calendar.DAY_OF_YEAR, day);
        return DateUtils.getThisWeekMonday(calendar.getTime());
    }

    private DemandForecast doForecast(String mobile, String userId, List<String> corpIdList, DemandForecastTypeEnum typeEnum, String monday) {
        if (Objects.isBlank(mobile)) {
            return null;
        }

        // 获取数据
        DemandForecast result = jdbcSession.findOne(DemandForecast.class).eq("userId", userId).and().eq("weekStartDate", monday)
                .and().eq("type", typeEnum.getType()).exe();
        if (result != null) {
            corpIdList.removeAll(result.getCorpIds());
            if (corpIdList.size() > 0) {
                result.getCorpIds().addAll(corpIdList);
                jdbcSession.updateById(result);
            }
            return result;
        }

        // 请求腾讯
        Credential credential = new Credential("AKIDylITWNIH3WkkX4Haw1pCQQAfwwualARX", "ynMemdF7k66tSqmTuCfrlSrzNbVGMDo4");
        DemandForecastClient forecastClient = new DemandForecastClient(credential);
        ForecastScoreResponse response = forecastClient.request(MD5.string2MD5(mobile), typeEnum.getVendorType());
        if (response == null) {
            return null;
        }

        // 获取登录用户
        String loginUserId = null;
        try {
            Subject subject = SubjectUtil.getSubject();
            loginUserId = subject.getUserId();
        } catch (Exception ignored) {
        }

        // 保存数据
        long time = System.currentTimeMillis();
        result = Pool.newInstance(DemandForecast.class);
        result.setCreateUserId(loginUserId);
        result.setSequence(time);
        result.setUpdateUserId(loginUserId);
        result.setMobile(mobile);
        result.setUserId(userId);
        result.setCorpIds(corpIdList);
        ForecastScoreDataObject[] dataList = response.getDataList();
        for (ForecastScoreDataObject each : dataList) {
            ForecastScoreData data = each.getData();
            result.setForecastValue(NumberUtils.toInt(data.getScoreGrade()));
        }
        result.setWeekStartDate(monday);
        result.setRequestId(response.getRequestId());
        result.setType(typeEnum.getType());
        jdbcSession.insert(result);

        // 保存排序数据
        demandForecastSequenceService.save(corpIdList, userId, time, typeEnum.getType());
        return result;
    }

}
